package com.tools.web.interceptor.auth._common;

import com.tools.common.object.Force;
import com.tools.common.object.Note;
import com.tools.common.object.json.JsonKit;
import com.tools.common.thread.Timeunit;
import com.tools.db.cache.local.LocalCache;
import com.tools.web.interceptor.auth.*;

import java.util.Objects;

/**
 * 使用 LocalCache 本地缓存实现的 “用户单在线记录” 的 AuthenticationManager 身份认证拦截器
 * */
@Note("使用 LocalCache 本地缓存实现的 “用户单在线记录” 的 AuthenticationManager 身份认证拦截器")
public abstract class LocalSingleAuthenticationManager extends GenericAuthenticationManager {

    @Note("本地缓存接口实例")
    private final LocalCache localCache;

    protected LocalSingleAuthenticationManager(LocalCache localCache, AuthSource source, AuthUserService authUserService) {
        super(source, authUserService);
        if(localCache == null) throw new NullPointerException("本地缓存接口实例为 null，构建 JWTLocalSingleAuthenticationManager 失败");
        this.localCache = localCache;
    }

    @Override
    public Timeunit getTimeunitUsedBySubclass() {
        return Timeunit.MILL;
    }


    @Override
    protected GetAuthUserResult getAuthUser(String key, AuthToken decryptedAuthToken) {
        String json = (String) this.localCache.get(key);
        //获取不到，那就是没有或者已过期
        if(json == null) {
            return super.protected_getResultIfExpired(decryptedAuthToken);
        }
        SingleAuthUser authUser = JsonKit.toEntity(json, SingleAuthUser.class);
        String srcUuid = authUser.getUuid();
        String srcDeviceTypeId = authUser.getLoginDeviceType();
        if(Objects.equals(srcUuid, decryptedAuthToken.getUuid()) &&
                Objects.equals(srcDeviceTypeId, decryptedAuthToken.getLoginDeviceType())) {
            return new GetAuthUserResult(true, authUser);
        }
        //若 UUID 和 设备类型对不上，那就说明有账户被人顶下线了，在线设备数不会自减
        return new GetAuthUserResult(false, null);
    }

    @Override
    protected void setAuthUser(String key, AuthUser srcAuthUser, AuthToken decryptedAuthToken) {
        SingleAuthUser authUser = (SingleAuthUser) srcAuthUser;
        authUser.setUuid(decryptedAuthToken.getUuid());
        authUser.setLoginUserType(decryptedAuthToken.getLoginUserType());
        authUser.setLoginUserType(decryptedAuthToken.getLoginUserType());
        String json = JsonKit.toJSON(authUser);
        this.localCache.put(key, json, decryptedAuthToken.getExpirationMill());
    }

    @Override
    protected void removeAuthUser(String key) {
        this.localCache.remove(key);
    }

    @Override
    protected void updateAuthUser(String key, AuthUser authUser) {
        Force<Object> force = new Force<Object>(authUser) {
            @Override
            public Object force(Object source) {
                String src = (String) source;
                if(src == null) return null;
                SingleAuthUser newAuthUser = this.getParam(0, SingleAuthUser.class);
                SingleAuthUser oldAuthUser = JsonKit.toEntity(src, SingleAuthUser.class);
                newAuthUser.copyAuthData(oldAuthUser);
                newAuthUser.copyCustomData(oldAuthUser);
                Object user = newAuthUser.getUser();
                oldAuthUser.setUser(user);
                return JsonKit.toJSON(oldAuthUser);
            }
        };
        this.localCache.modify(key, force);
    }

    @Override
    protected void protected_loginOut(String key, String loginDeviceType, String uuid) {
        this.removeAuthUser(key);
    }
}
